package Webpacus::Controller::Search;

use strict;
use warnings;
use base 'Catalyst::Controller';

use lib '/data/webpac2/lib';
use WebPAC::Search::Estraier 0.03;
use Data::SpreadPagination;


=head1 NAME

Webpacus::Controller::Search - Search WebPAC data

=head1 SYNOPSIS

See L<WebPAC>, L<Webpacus>

=head1 DESCRIPTION

Catalyst Controller for search fields Hyper Estraier

=head1 METHODS

=over 4

=item default

=cut

sub default : Private {
    my ( $self, $c ) = @_;

	$c->log->dumper($c->req->params, 'params');

    $c->stash->{template} = 'search.tt';
}

=item suggest

Returns results for REST URIs like:

C<search/suggest?search=FieldName&show=TitleProper&FieldName=query%20string>

It will use C<search> field to filter results (and using additional
C<FieldName> as value of search) and return C<TitleProper> field
for results.

If C<search> field has magic value <all>, it will search over all data, not
just one specified field:

C<search/suggest?search=all&show=TitleProper&all=query%20string>

=cut

sub suggest : Local {
	my ( $self, $c ) = @_;

	my $search = $c->req->params->{search};
	my $show = $c->req->params->{show};

	my $log = $c->log;

	my $webpac = $c->comp('Model::WebPAC');
	#$c->log->dumper( $c->stash, 'stash' );
	$webpac->setup_site( $c->stash->{site} );

	my $q = $c->req->params->{ $search || 'all' } || $c->response->body("no results");

	$log->info("search for '$q' in $search and display $show\n");

	my $hits_on_page = $c->config->{'hits_for_suggest'};
	if (! $hits_on_page) {
		$log->info("hits_for_suggest isn't defined, defaulting to 10");
		$c->config->{'hits_for_suggest'} = 10;
		$hits_on_page = 10;
	}

	$c->forward('filter_database');

	my $hits = $webpac->search(
		phrase => $q,
		add_attr => $c->stash->{attr},
		get_attr => [ $show ],
		hits_on_page => $hits_on_page,
	);

	my $used;
	my @suggestions;

	foreach my $res (@{$hits}) {
		my $v = $res->{ $show } || next;
		next if ($used->{ $v }++);
		push @suggestions, $v;
	}

	$log->debug( ($#suggestions + 1) . " unique hits returned");

	$c->response->body( $c->prototype->auto_complete_result( \@suggestions ) );
}


=item results

Returns results for search query

=cut

sub results : Local {
	my ( $self, $c ) = @_;

	my $params = $c->req->params;

	# do full-page refresh for clients without JavaScript
	$c->stash->{results} = $c->subreq('/search/results/ajax', {}, $params);
   	$c->stash->{template} = 'search.tt';
}


=item results_ajax

Private method which uses C<Model::WebPAC> and returns results for search
query It generatets just I<inner> HTML for results div, so it has C<_ajax>
in name.

=cut

# specify all Hyper Estraier operators which should stop this module
# from splitting search query and joining it with default operator
my $hest_op_regex = '(:?\[(:?BW|EW|RX)\]|AND|OR|ANDNOT)';

sub results_ajax : Path( 'results/ajax' ) {
	my ( $self, $c ) = @_;

	my $params = $c->req->params;
	my $webpac = $c->comp('Model::WebPAC');
	$webpac->setup_site( $c->stash->{site} );
	my $log = $c->log;

	$log->dumper($params, 'params');

	if (! $params->{_page} || $params->{_page} < 1) {
		$params->{_page} = 1;
		$log->warn("fixed _page parametar to 1");
	}

	my @words;
	# default operator to join fields/words
	my $operator = 'AND';

	foreach my $f (keys %{ $params }) {

		next if ($f =~ m/^_/o);

		my $v = $params->{$f} || next;

		if (my $op = $params->{ '_' . $f}) {
			if ($v =~ /$hest_op_regex/) {
				# don't split words if there is Hyper Estraier
				# operator in them
				push @words, $v;
			} else {
				push @words, join(" $op ", split(/\s+/, $v) );
			}
		} else {
			push @words, $v;
		}

		next if ($f eq 'all');	# don't add_attr for magic field all

		if ($v !~ /\s/) {
			push @{ $c->stash->{attr} }, "$f ISTRINC $v";
		} else {
			map {
				push @{ $c->stash->{attr} }, "$f ISTRINC $_";
			} grep { ! /$hest_op_regex/ } split(/\s+/, $v);
		}
	}

    $c->forward('filter_database');

	my $q = join(" $operator ", @words);

	my $template = $params->{'_template'} || $c->config->{webpac}->{template};

	$log->die("can't find _template or default from configuration!") unless ($template);

	my $hits_on_page = $c->config->{'hyperestraier'}->{'hits_on_page'} || 10;

	$log->debug("using template $template to produce $hits_on_page results");
	$c->stash->{current_template} = $template;

	$c->stash->{html_results} = $webpac->search( 
			phrase => $q,
			template => $template,
			add_attr => $c->{stash}->{attr},
			get_attr => [ '@uri' ],
			hits_on_page => $hits_on_page,
			page => $params->{'_page'},
	);

	$c->stash->{hints} = $webpac->hints;

	$c->stash->{phrase} = $q;
	$c->stash->{page} = $params->{_page};
	$c->stash->{hits_on_page} = $hits_on_page;

	# create pager
	$c->stash->{pager} = new Data::SpreadPagination({
		totalEntries => $webpac->hints->{hit},
		entriesPerPage => $hits_on_page,
		currentPage => $params->{_page},
		maxPages => $c->config->{pager}->{max_pages} || 10,
	});

	my $site_uri_params = $params;

	map {
		delete( $site_uri_params->{$_} ) unless ( $site_uri_params->{$_} );
	} keys %{ $site_uri_params };

	$c->stash->{site_uri_params} = sub {

		my $s_params;

		# shallow copy
		map { $s_params->{$_} = $site_uri_params->{$_} } keys %{ $site_uri_params };

		my $n_params = shift;
		foreach my $p (keys %{ $n_params }) {
			if (! $n_params->{$p}) {
				delete($s_params->{$p});
			} else {
				$s_params->{$p} = $n_params->{$p};
			}
		}

		#$c->log->dumper( $s_params, 'site_uri_params' );
		return $c->uri_for('results', $s_params)->as_string;
	};

	$c->stash->{template} = 'results.tt';

}

=item filter_database

Takes C<< $c->req->params >> and adds Hyper Estraier
filters for checked databases to C<< $c->stash->{attr} >>.

=cut

sub filter_database : Private {
	my ( $self, $c ) = @_;

	my $params = $c->req->params;

	if ($params->{_database}) {
		my $type = $c->config->{hyperstraier}->{type} || 'search';
		my $attr;
		if (ref($params->{_database}) eq 'ARRAY') {
			# FIXME do we need to add $ at end?
			$attr .= '(' . join("|",@{$params->{_database}}) . ')';
		} else {
			$attr .= $params->{_database};
		}
		push @{ $c->stash->{attr} }, '@uri STRRX /' . $type . '/' . $attr . '/';
		$c->log->debug("filter_database: " . join(",", @{ $c->stash->{attr} }) );
	}


}

=item record

forwarded to C</editor/record>

=cut

sub record : Local {
	my ( $self, $c ) = @_;

	$c->detach( '/editor/record' );
}

=back

=head1 AUTHOR

Dobrica Pavlinusic C<< <dpavlin@rot13.org> >>

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;
